package com.soap.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.crypto.digest.DigestUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.soap.commons.RedisKeys;
import com.soap.commons.ReturnCommons;
import com.soap.commons.validators.GroupA;
import com.soap.entity.domain.Token;
import com.soap.entity.dto.UserDto;
import com.soap.entity.po.User;
import com.soap.entity.query.UserQuery;
import com.soap.entity.vo.UserLoginVo;
import com.soap.feign.service.MSSearchServiceFeign;
import com.soap.jwt.JwtProperties;
import com.soap.manager.UserManager;
import com.soap.service.UserService;
import com.soap.utils.HttpclientTools;
import com.soap.utils.JedisTools;
import com.soap.utils.JwtUtils;
import com.soap.utils.ValidateUtils;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.CrossOrigin;

import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

/**
 * @Description
 * @Author ZhangPY
 * @Date 2020/5/28
 */
@CrossOrigin
@Log4j2
@Service
public class UserServiceImpl implements UserService {

    @Value("${wx.appid}")
    private String appid;
    @Value("${wx.secret}")
    private String secret;
    @Value("${wx.token_url}")
    private String tokenUrl;
    @Value("${wx.user_url}")
    private String userUrl;
    @Autowired
    private UserManager userManager;
    @Autowired
    private JwtProperties jwtProperties;
    @Autowired
    private JedisTools jedisTools;
    @Autowired
    private MSSearchServiceFeign msSearchServiceFeign;


    @Override
    public String addUserByPhone(UserDto userDto) {

        Map<String , Object> result = new HashMap<>();

        String groupErrorsOne = ValidateUtils.getGroupErrorsOne(userDto, GroupA.class);
        if (StringUtils.isNotBlank(groupErrorsOne)) {
            result.put("success" , false);
            result.put("msg" , groupErrorsOne);
            return JSONObject.toJSONString(result);
        }

        User user = new User();
        /** 属性拷贝 **/
        BeanUtil.copyProperties(userDto , user);
        /** 属性赋值 **/
        user.setCreateTime(LocalDateTime.now());
        user.setUpdateTime(LocalDateTime.now());
        /** 密码加密 **/
        user.setPassword(DigestUtil.md5Hex(user.getPassword()));

        /** 插入 **/
        boolean save = userManager.save(user);
        if (save) {
            result.put("success" , true);
            result.put("data" , user);
            /** 调用es插入 **/
            msSearchServiceFeign.insertUser(BeanUtil.beanToMap(user));
        } else {
            result.put("success" , true);
            result.put("msg" , "新增成功");
        }

        return JSONObject.toJSONString(result);
    }


    @Override
    public String accredit(UserLoginVo userLoginVo) {

        Map<String , Object> result = new HashMap<>();
        /** 参数校验 **/
        String groupErrorsOne = ValidateUtils.getGroupErrorsOne(userLoginVo, GroupA.class);
        if (StringUtils.isNotBlank(groupErrorsOne)) {
            result.put("success" , false);
            result.put("msg" , groupErrorsOne);
            return JSONObject.toJSONString(result);
        }
        String md5PassWord = DigestUtil.md5Hex(userLoginVo.getPassword());
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.eq("phone_num" , userLoginVo.getPhoneNum());
        wrapper.eq("password" , md5PassWord);
        wrapper.last("limit 1");
        List<User> list = userManager.list(wrapper);
        if (list.size() == 0) {
            result.put("success" , false);
            result.put("msg" , "用户名或密码错误");
            return JSONObject.toJSONString(result);
        }
        String token = null;
        /** 生成token **/
        token = UUID.randomUUID().toString().replaceAll("-","");
        /** 写入redis **/
        jedisTools.setex(RedisKeys.LOGIN_INFO+token, 3600, JSONObject.toJSONString(list.get(0)));

        if (StringUtils.isNotBlank(token)) {
            result.put("success" , true);
            result.put("token" , token);
            result.put("data" , list.get(0));

        } else {
            result.put("success" , false);
            result.put("msg" , "系统异常");
        }
        return JSONObject.toJSONString(result);
    }


    @Override
    public String checkToken(String token) {

        Map<String, Object> infoFromToken = new HashMap<>();
        try {
            infoFromToken = JwtUtils.getInfoFromToken(token, this.jwtProperties.getPublicKey());
            long now = System.currentTimeMillis();
            long exp = (long)infoFromToken.get("exp");

            if (exp > now) {
                return "已过期!";
            }

        } catch (Exception e) {
            e.printStackTrace();
            log.error("校验token异常");
        }


        return JSONObject.toJSONString(infoFromToken);
    }

    @Override
    public String getUserListByPage(UserQuery userQuery) {
        Page<User> page = new Page<>(userQuery.getPage(), userQuery.getLimit());
        IPage<User> userList = userManager.page(page);

        return ReturnCommons.getSuccess(userList);
    }

    @Override
    public String lockOrUnLockUser(Long userId, Boolean lockedState) {
        if (userId == null || lockedState == null) {
            return ReturnCommons.getFail("参数异常");
        }
        User user = new User();
        user.setId(userId).setIsLocked(lockedState);
        boolean updateUser = userManager.updateById(user);
        if (updateUser) {
            return ReturnCommons.getSuccess();
        } else {
            return ReturnCommons.getFail();
        }
    }

    @Override
    public String getUserById(Long userId) {
        if (userId == null) {
            return ReturnCommons.getFail("参数异常");
        }
        return ReturnCommons.getSuccess(userManager.getById(userId));
    }

    @Override
    public String updateUser(User userDto) {
        boolean update = userManager.updateById(userDto);
        if (update) {
            return ReturnCommons.getSuccess();
        } else {
            return ReturnCommons.getFail();
        }
    }

    @Override
    public String WxCallback(String code) {

        Map<String , Object> result = new HashMap<>();

        /** 定义获取微信token地址 */
        String tokenUrls = String.format(tokenUrl,appid,secret,code);
        /** 发送请求 */
        String tokenResult = HttpclientTools.doGet(tokenUrls);
        /** json转换 */
        Token token = JSON.parseObject(tokenResult, Token.class);
        if (token != null && StringUtils.isNotBlank(token.getAccess_token()) && StringUtils.isNotBlank(token.getOpenid())) {
            /** 定义根据用户openid获取用户昵称头像等信息 */
            String userUrls = String.format(userUrl,token.getAccess_token(),token.getOpenid());
            /** 发送请求 */
            String userResult = HttpclientTools.doGet(userUrls);
            /** json转换 */
            User user = JSON.parseObject(userResult, User.class);

            if (user != null && StringUtils.isNotBlank(user.getOpenid())) {
                /** 此处user不为空标识用户授权成功，对应的也是登陆成功，后面处理自己的业务逻辑如果数据库有openId拉取该用户对应的资源权限
                 *  如果没有标识新用户，则走注册流程，具体细节具体场景 */
                /** 根据openId查询 **/
                QueryWrapper<User> wrapper = new QueryWrapper<>();
                wrapper.eq("openid" , user.getOpenid());
                User one = userManager.getOne(wrapper);

                /** 生成token **/
                String tokens = UUID.randomUUID().toString().replaceAll("-","");

                /** 插入one **/
                if (one == null) {
                    userManager.save(user);
                }
                User managerOne = userManager.getOne(wrapper);


                /** 写入redis **/
                jedisTools.setex(RedisKeys.LOGIN_INFO+tokens, 3600, JSONObject.toJSONString(managerOne));

                if (StringUtils.isNotBlank(tokens)) {
                    result.put("success" , true);
                    result.put("token" , tokens);
                    result.put("data" , managerOne);

                } else {
                    result.put("success" , false);
                    result.put("msg" , "系统异常");
                }

            }
        }
        return JSONObject.toJSONString(result);
    }
}
